function parseXML(XMLstr) {
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(XMLstr, 'text/xml');
  const taskNodes = xmlDoc.getElementsByTagName('bpmn2:task');
  const serviceList = Array.from(taskNodes)
    .flatMap((taskNode) => Array.from(taskNode.childNodes)) // get task children
    .filter((taskChild) => taskChild.nodeName === 'bpmn2:extensionElements') // filter extension elements
    .flatMap((taskChild) => Array.from(taskChild.childNodes)) // get extension nodes
    .filter(((extensionNode) => extensionNode.nodeName === 'camunda:properties')) // filter properties
    .map((extensionNode) => Array.from(extensionNode.childNodes)) // get property nodes
    .map((propertyNodes) => propertyNodes
      .filter((propertyNode) => propertyNode.nodeType === 1) // filter nodeType === 1
      .reduce((label, propertyNode) => {
        const re = label;
        switch (propertyNode.attributes.name.nodeValue) {
          case 'arguments': {
            const paramNodes = Array.from(propertyNode.childNodes);
            re.taskId = propertyNode.parentNode.parentNode.parentNode.attributes.id.nodeValue;
            re.params = paramNodes
              .filter((node) => node.nodeType === 1)
              .reduce((params, node) => ({
                ...params,
                [node.attributes.name.nodeValue]: node.attributes.value.nodeValue,
              }),
              {});
            break;
          }
          case 'instances': {
            const instances = Array.from(propertyNode.childNodes);
            re.instances = instances
              .filter((node) => node.nodeType === 1)
              .reduce((instance, node) => ({
                ...instance,
                [node.attributes.name.nodeValue]: node.attributes.value.nodeValue,
              }), {});
            break;
          }
          case 'instanceUrls': {
            // should only be touched by backend service
            break;
          }
          case 'input': {
            const paramNodes = Array.from(propertyNode.childNodes);
            re.taskId = propertyNode.parentNode.parentNode.parentNode.attributes.id.nodeValue;
            re.input = paramNodes
              .filter((node) => node.nodeType === 1)
              .reduce((params, node) => ({
                ...params,
                [node.attributes.name.nodeValue]: node.attributes.value.nodeValue,
              }),
              {});
            break;
          }
          default: {
            const name = propertyNode.attributes.name.nodeValue;
            const value = propertyNode.attributes.value.nodeValue;
            re[name] = value;
          }
        }
        return re;
      }, {})); // initial value for label is {}
  return serviceList;
}

function getFirstTask(XMLstr) {
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(XMLstr, 'text/xml');
  const taskId = xmlDoc.getElementsByTagName('bpmn2:task')[0].getAttribute('id');
  return taskId;
}

function filterTaskInstances(XMLstr) {
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(XMLstr, 'text/xml');
  const taskNodes = xmlDoc.getElementsByTagName('bpmn2:task');
  Array.from(taskNodes)
    .forEach((taskNode) => {
      Array.from(taskNode.childNodes)
        .filter((taskChild) => taskChild.nodeName === 'bpmn2:extensionElements')
        .forEach((extEl) => Array.from(extEl.childNodes)
          .filter((extNode) => extNode.nodeName === 'camunda:properties')
          .forEach((propsNode) => Array.from(propsNode.children)
            .filter((propNode) => propNode.attributes.getNamedItem('name').value === 'instances' || propNode.attributes.getNamedItem('name').value === 'instanceUrls')
            .forEach((instanceNode) => propsNode.removeChild(instanceNode))));
    });
  return (new XMLSerializer()).serializeToString(xmlDoc);
}

export {
  parseXML,
  getFirstTask,
  filterTaskInstances,
};
